"""
作者：tiandongjun
功能：模拟GA1400服务器
日期 版本:
2019-03-21 1.0：可以运行，接收注册，心跳，图片下载功能
2019-03-23 2.0：加入try 异常保护
2019-03-27 3.0: 增加Face，File，Video，校时处理，增加返回400错误信息描述，增加logging
2019-04-03 4.0: 简化代码，增加注销流程（先回401，再注销）,增加函数runOnce,增加判断图片格式是否正确（0xffd8开始，0xffd9结束）
2019-04-15 5.0: 返回值201错误时，添加原因
2019-04-23 6.0: 增加超时3600s后重置nonce，增加每个消息判断是否有Auth字段（如果有进行认证）
2019-04-30 7.0: 增加错误原因打印消息，增加判断是否保存图片
2019-05-10 8.0: 修改logging打印的内容
2019-06-11 9.0: 接收图片如果有大图为0或小图为0时，依然返回正确给前端
2019-08-08 11.0: 增加协议，解析人员对象属性
2019-09-09 12.0: 增加是否判断图片格式选项
2019-09-19 13.0:  增加统计图片数量功能
2019-10-14 14.0:  图片命名增加FaceID
2019-11-1  15.0: logging部分修改
2020-04-10  15.1: 将检查图片格式，获取人脸小图人员小图封装为单独函数，减少代码数；修改一个问题（统计Files时，统计的确是Video总数）;
                    pc时间被修改，增加处理（返回401重新注册，原因：pc time is modified）
2020-04-24  15.2: 增加图片接收时间和shottime之间时间差的计算，用 datetime
2020-05-09  15.3: 增加卡口机动车、非机动车,重构代码方便扩展功能
2020-05-26  15.4: 所有json数据属性
2020-06-04  15.5: 回复消息 RequestURL=/VIID/...,  ResponseStatusListObject
2020-09-02  15.6: 根据Type字段获取图片类型，定义define_jpgtype，保存图片名称更新为图片类型。
2020-09-21  v2:   封装GA类
2020-12-21  v2:    解析所有json数据 get_jsonkeys.py
2021-05-19  v3:  增加ssl，支持https
2021-07-26      增加 updateRegister，控制服务器是否给前端发刷新注册
2021-08-10      增加接收数据错误时，保存接收的数据，增加数据库写入
流程：
1，接收注册消息，检查授权，注册成功更新变量dict（ip：注册时间，nonce）
2，接收其他消息，检查授权，保存图片
3，统计图片，序列化结果
"""

"""
注册
POST /VIID/System/Register HTTP/1.0
Host: 10.90.24.2:12345
Content-Type:application/VIID+JSON
Content-Length:35

{"RegisterObject":{"DeviceID":"1"}}
"""
import http.server
import socketserver
import json,time,base64
import os,logging
from logging.handlers import RotatingFileHandler
import random, hashlib
import threading
import string
import configparser
import datetime
import socket
import get_jsonkeys
import ssl
import gadb_sqlite

VERSION = '16.0'
timeout = 3600  # 3600s
updateRegister = 0 # 服务器不向前端发刷新注册
password = '12345678'
IP = ""
PORT = 8898
loglevel = 0 # low -> high 0 - 1
save_json = 0
save_jpg = 0
show_registertime = 0  # 1： 显示注册信息
usegaini = 0  # 1: 使用ga.ini文件 返回消息
noparseID = 0 # 1: 不解析Object，直接返回200
check_jpg = 0   # 1： 如果图片错误回复错误消息
check_auth = 0 # 0:消息没有携带Auth， 1：每个消息都携带Auth
use_sqlite3 = 1
galibLock = threading.Lock()

server_runtime = [0]
device_registerinfo = {}  # 前端注册信息 
#{ip: {"registertime":'111', 'nonce':***, 'record_registertime':[], 'refresh_registertime':[],
#      'unregistertime':['2',], 'result':["/VIID/Faces":[],"/VIID/Files":[],..]}, 
# ip2:{...   }   }
GAlogging = logging.getLogger('GAHttps')
allThreads = [] # 所有线程
threadNumsLock = threading.Lock() # 读取线程数量的线程锁
resultLock = threading.Lock()
class GALog():
    def __init__(self):
        pass
    
    def info(self, msg):
        try:
            mylogging.info(msg)
        except Exception as e:
            mylogging.error(msg + ' , repeat because of   ' + str(e))
            
    def error(self, msg):
        try:
            mylogging.error(msg)
        except Exception as e:
            mylogging.error(msg + ' , repeat because of   ' + str(e))
    
    def warning(self, msg):
        try:
            mylogging.warning(msg)
        except Exception as e:
            mylogging.error(msg + ' , repeat because of   ' + str(e))

"""   
使用自定义类，再次封装 logging 使用方法
1, 修改 GAlogging = logging.getLogger('GAHttps') ==> mylogging = logging.getLogger('GAHttps')
2, 修改 init_loggingSetGA 中的 GAlogging ==> mylogging
3, 增加 GAlogging = GALog()
"""  

class GAHttps():
    def __init__(self):
        self.httpd = None
        self.mkdir()        
        self.introMsg = 'GA1400服务器(https)信息\n'
        self.introMsg += "***********************************\n"
        self.introMsg += "server version is " + VERSION + '\n'
        self.introMsg += "前端注册密码：" + password + '\n'
        self.introMsg += "注册超时时间: " + str(timeout) + 's' + '\n'
        self.introMsg += "***********************************" + '\n'  
        self.introMsg += """图片命名：
        ip_PersonID_ImageID_Shottime_PersonObject_场景图.jpg
        ip_ImageID_Shottime_Image.jpg
        ip_FileID_FileName
        ip_VideoID_Begintime_Endtime.ps"""   + '\n' 
        print(self.introMsg)
        # 说明
        self.infomsg = '说明:\n'
        self.infomsg += '1, 服务器启动时间：点击启动GA1400按钮的时间，启动服务器后会删除所有前端的注册时间和图片信息，之后开始统计前端的注册时间和图片等信息\n'
        self.infomsg += '2, 如果把pc时间向前修改（比前端注册时间早），会删除该前端的注册信息，之后开始统计该前端的注册时间和图片信息\n'
        self.infomsg += '3, 注册时间: 前端发送不带Authorization的注册后删除注册时间和创建nonce，再发送带Authorization注册，认证成功后则保存时间\n'
        self.infomsg += '4, 注册时间列表：记录所有前端发送带Authorization注册消息，认证成功后则保存时间\n'
        self.infomsg += '5, 刷新注册时间列表：超时%ds后则保存时间，回复401要求重新注册认证\n'%timeout
        self.infomsg += '6, 注销时间列表：前端发送注销消息，认证成功后则保存时间，同时删除注册时间和nonce\n'
        
    def run(self, IP, PORT):   
        '''启动httpserver'''
        if threadNumsLock.locked():
            threadNumsLock.release()
        if resultLock.locked():
            resultLock.release()  
        if galibLock.locked():
            galibLock.release()  
        init_loggingSetGA()
        GAlogging.info(self.introMsg)
        GAlogging.info(self.infomsg)
        try:
            context = None
            if os.path.isfile("xxx.pem")==False or os.path.isfile("xxx.key")==False:
                GAlogging.error('GA1400服务器(https)启动失败，IP地址,端口:(%s , %d)'%(IP, PORT) + ", 没有找到证书:xxx.pem 或私钥:xxx.key") 
                return                
            context = ssl.SSLContext(ssl.PROTOCOL_TLS)
            #context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)                
            context.load_cert_chain("xxx.pem","xxx.key")#自己添加
            self.httpd = socketserver.ThreadingTCPServer((IP, PORT), Handler) 
            GAlogging.info('支持 https') 
            self.httpd.socket = context.wrap_socket(self.httpd.socket, server_side = True)
            # 使用多线程TCP服务器
            server_runtime[0] = time.time()
            device_registerinfo.clear()
            GAlogging.info('删除所有设备的注册信息')  
            GAlogging.info('GA1400服务器(https)已启动，IP地址,端口:(%s , %d)'%(IP, PORT))
            self.httpd.serve_forever()
        except Exception as e:
            GAlogging.error('GA1400服务器(https)启动失败，IP地址,端口:(%s , %d)'%(IP, PORT) + ", " + str(e))   

    def stop(self):
        # 停止 httpserver
        if threadNumsLock.locked():
            threadNumsLock.release()
        if resultLock.locked():
            resultLock.release()
        if galibLock.locked():
            galibLock.release()
        if self.httpd == None:
            GAlogging.info("GA1400服务器(https)未启动")
        elif self.httpd.fileno() > 0:    
            self.httpd.shutdown()        
            self.httpd.server_close()
            GAlogging.info("GA1400服务器(https)停止")
        
    def mkdir(self):
        # 创建目录存储log 和 图片
        if not os.path.isdir("GAHttps/video_ps"):
            os.makedirs("GAHttps/video_ps")
        if not os.path.isdir("GAHttps/file"):
            os.makedirs("GAHttps/file")
        if not os.path.isdir("GAHttps/face_jpg"):
            os.makedirs("GAHttps/face_jpg")
        if not os.path.isdir("GAHttps/person_jpg"):
            os.makedirs("GAHttps/person_jpg")
        if not os.path.isdir("GAHttps/image_jpg"):
            os.makedirs("GAHttps/image_jpg")
        if not os.path.isdir("GAHttps/motorvehicle_jpg"):
            os.makedirs("GAHttps/motorvehicle_jpg")
        if not os.path.isdir("GAHttps/nonmotorvehicle_jpg"):
            os.makedirs("GAHttps/nonmotorvehicle_jpg")
        if not os.path.isdir("GAHttps/log"):
            os.makedirs("GAHttps/log")
        
def init_loggingSetGA():
    """ 初始化logging设置，将打印信息分别记录到文件和屏幕上 """    
    #CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET              
    # 打印到文件
    localtime = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
    logFilename = "GAHttps/log/" + localtime + "_GAT1400.log"
        
    logging.basicConfig(level=logging.DEBUG,format='%(asctime)s [line:%(lineno)d] %(filename)s %(levelname)-8s %(message)s')    
    #logging.basicConfig(level=logging.DEBUG,format='%(asctime)s [line:%(lineno)d] %(levelname)-8s %(message)s')    
    # datefmt='%a, %d %b %Y %H:%M:%S',
    GAlogging.handlers=[]
    # 定义一个RotatingFileHandler，最多备份5个日志文件，每个日志文件最大10M
    Rthandler = RotatingFileHandler(logFilename, maxBytes=50 * 1024 * 1024, backupCount=50)
    Rthandler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s [line:%(lineno)d] %(filename)s %(levelname)-8s %(message)s') 
    #formatter = logging.Formatter('%(asctime)s [line:%(lineno)d] %(levelname)-8s %(message)s') 
    Rthandler.setFormatter(formatter)
    GAlogging.addHandler(Rthandler)   
    
class Handler(http.server.BaseHTTPRequestHandler):
    def savedata(self, filename, data):    
        # 保存 二进制 文件
        try:
            with open(filename, 'wb') as f:
                f.write(data)
        except Exception as e:
            GAlogging.error(self.ip_port + '写{},出现异常:'.format(filename) + str(e))
            
    def create_nonce(self):
        # ------------有新连接时，产生随机数-------------------
        chars = string.ascii_letters + string.digits
        nonce = ''
        for i in range(64):
            nonce += ''.join(random.sample(chars, 1))
        return nonce
                    
    def check_jpgformat(self, filename, jpg):
        """
        检查图片格式
        jpg: 图片二进制数据
        filename：文件名
        return: False 返回错误
        """
        if jpg[:2] != b'\xff\xd8' or jpg[-2:] != b'\xff\xd9':
            jpg_head_hex = "".join(["%02X " % x for x in jpg[:2]]).strip()
            jpg_end_hex = "".join(["%02X " % x for x in jpg[-2:]]).strip()
            GAlogging.warning(self.ip_port + "注意：{}格式错误开始2字节: {},结束2字节: {}".format(filename, jpg_head_hex, jpg_end_hex))    
            self.savedata(filename, jpg)
            self.errpicsum += 1
            if check_jpg == 1:
                return False
        return True
    
    def check_Authorization(self, digest, noncestr):
        """
        功能：检查digest中的授权信息，认证失败返回False，并回复401鉴权挑战
        :param in
        digest: http中的Authorization: Digest username=..., realm=...,
        noncestr: 全局变量nonce（服务器返回401时生成的nonce值，保存在一全局变量中）
        :return True：根据计算nonce中的，认证成功
        """        
        username = realm = uri = nonce = nc = cnonce = qop = response = None
        # 1 取值
        Authorization_str = digest.split(",")
        for a in Authorization_str:
            param = a.strip()
            if param.startswith('Digest username='):
                username = param[len('Digest username='):].strip().strip('"')
            elif param.startswith('realm='):
                realm = param[len('realm='):].strip().strip('"')
            elif param.startswith('uri='):
                uri = param[len('uri='):].strip().strip('"')                
            elif param.startswith('nonce='):
                nonce = param[len('nonce='):].strip().strip('"')
            elif param.startswith('nc='):
                nc = param[len('nc='):].strip().strip('"')           
            elif param.startswith('cnonce='):
                cnonce = param[len('cnonce='):].strip().strip('"')
            elif param.startswith('qop='):
                qop = param[len('qop='):].strip().strip('"')
            elif param.startswith('response='):
                response = param[len('response='):].strip().strip('"')
        if username is None or realm is None or uri is None or nonce is None or nc is None or cnonce is None or qop is None or response is None:
            GAlogging.error(self.ip_port + ' Digiest : ' + digest)
            others = "Digiest error"
            self.response_401(others)
            return False
            
        # 2 检查nonce        
        if nonce != noncestr:         
            msg = "nonce 错误" + " ,客户端携带的nonce:" + nonce+ " ,全局变量中的nonce:" + noncestr
            GAlogging.error(self.ip_port + msg + '\n Digiest : ' + digest)
            others = "nonce error"
            self.response_401(others)
            return False
        
        # 3 计算公式
        A1 = username + ":" + realm + ":" + password
        A2 = "POST:" + uri

        m2 = hashlib.md5()
        m2.update(A1.encode('utf-8'))
        HA1 = m2.hexdigest()

        m2 = hashlib.md5()
        m2.update(A2.encode('utf-8'))
        HA2 = m2.hexdigest()

        response_str = HA1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + HA2
        m2 = hashlib.md5()
        m2.update(response_str.encode('utf-8'))
        response_md5 = m2.hexdigest()
        # 4 判断计算得到的response与digest中值是否一样
        if response_md5 == response:
            GAlogging.info(self.ip_port + '认证成功')
            return True
        errmsg = "response计算结果与客户端携带的不一样"        
        errmsg +="\n\t ,username={},realm={},uri={},nonce={},nc={},cnonce={},qop={}".format(username, realm, uri, nonce, nc, cnonce, qop)
        errmsg += "\n\t ,客户端携带response:" + response
        errmsg += "\n\t ,计算的response:" + response_md5
        GAlogging.error(self.ip_port + errmsg + '\n' + " Digest: " + digest)      
        others = "Authentication failed"
        self.response_401(others)
        return False
    
    def check_regtime_auth(self):
        # 检查全局变量中的注册时间 正常返回True， 错误返回False ，并回复401鉴权挑战 
        # return False 返回错误
        ip = self.client_address[0]
        # 1, 获取当前时间
        curtime = time.time()
        # 2, 获取IP，注册时间
        if self.get_device_ip() == None:  
            others = "%s not register"%ip
            self.response_401(others)
            return False
        regtime_1 = self.get_device_registertime()
        if regtime_1 == None: 
            others = "not found %s registertime"%ip
            self.response_401(others)
            return False
        # 3 获取 注册时间 列表
        regtime_list = self.get_device_recordregtime()  
        if regtime_list == None: 
            others = "not found %s registertime list"%ip
            self.response_401(others)
            return False
        regtime = regtime_list[-1] # 最近的注册时间            
        # pc时间小于 注册时间 ， 删除该ip的注册信息，重新注册
        if curtime < regtime:
            others = "pctime < registertime" 
            others += ", pctime:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime)))
            others += ", registertime:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(regtime)))
            self.del_device_ip()
            GAlogging.error(self.ip_port + others + ' , %s注册信息已删除, 需要重新注册'%ip)
            self.response_401(others)                                 
            return False            
        # 4，pc时间 比注册时间 超时，回复401鉴权挑战  
        if updateRegister == 1:
            if curtime - regtime >= timeout:
                others = "pctime-registertime=%d >= %d s"%(curtime-regtime, timeout)
                others += ", pctime:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime)))
                others += ", registertime:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(regtime)))
                refreshtime_list = self.get_device_refreshregtime()
                if refreshtime_list:
                    refreshtime = refreshtime_list[-1]
                    if curtime - refreshtime <= timeout: # 如果 当前时间 与 刷新时间差小于3600
                        pass       # 不需更新刷新注册时间
                    else:
                        self.set_device_refreshregtime(curtime)  # 设置刷新注册时间
                        GAlogging.info(self.ip_port + "更新刷新注册时间:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime))))
                        self.response_401(others)  
                else:
                    self.set_device_refreshregtime(curtime)  # 设置刷新注册时间
                    GAlogging.info(self.ip_port + "设置刷新注册时间:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime))))
                    self.response_401(others)              
                return False            
        # 5, 每个消息都检查Auth
        if check_auth == 1: 
            digest = self.headers.get("Authorization") 
            if digest == None:
                others = "not found Authorization"
                self.response_401(others)
                return False           
            nonce = self.get_device_nonce()
            if nonce == None:
                others = "not found %s nonce"%ip
                self.response_401(others)
                return False
            # 检查认证是否成功
            if self.check_Authorization(digest, nonce) == False:
                return False
        return True
            
    def response_useinifile(self):
        # return True 使用ga.ini
        if usegaini == 1:
            if os.path.isfile("ga.ini"):                
                try:
                    conf = configparser.ConfigParser()
                    conf.read('ga.ini')
                    if "Register" in self.RequestURL:        # 注册和注销
                        rcode = conf.get("httpregister",'code')
                        expires = conf.get("httpregister",'expires')
                        content_type = conf.get("httpregister",'content-type')
                        content_str=conf.get("httpregister",'content')
                    elif "Keepalive" in self.RequestURL:     # 心跳
                        rcode = conf.get("httpkeepalive",'code')
                        expires = conf.get("httpkeepalive",'expires')
                        content_type = conf.get("httpkeepalive",'content-type')
                        content_str=conf.get("httpkeepalive",'content')
                    else:
                        sel = conf.get("sel",'usehttp')
                        if sel=='1':        
                            # http格式回复消息
                            rcode = conf.get("httppic",'code')
                            expires = conf.get("httppic",'expires')
                            content_type = conf.get("httppic",'content-type')
                            content_str=conf.get("httppic",'content')
                        else:               
                            # tcp格式回复消息
                            conn=self.request
                            msg = conf.get("other",'msg')  
                            closesocket = conf.get("other",'closesocket')  
                            infomsg = '返回 ga.ini中定义消息 TCP: ' + msg
                            infomsg +=" ,RequestURL:" + self.RequestURL
                            infomsg +=" ,返回消息时长:" + "%.06f"%(time.time()-self.usetime) + 's'
                            GAlogging.info(self.ip_port + infomsg)
                            back_data = msg.encode('utf8')
                            conn.sendall(back_data) 
                            if closesocket=='1':
                                conn.close()  
                            return True
                    content_len = len(content_str)
                    self.send_response_only(int(rcode))
                    self.send_header("Expires", expires)
                    self.send_header("Content-type", content_type)                
                    self.send_header("Content-Length", str(content_len))
                    self.end_headers()
                    content_bytes = content_str.encode("utf-8")
                    self.wfile.write(content_bytes)  # 返回给client数据 
                    infomsg = '返回 ga.ini中定义消息 http:' + rcode
                    infomsg +=" ,RequestURL:" + self.RequestURL
                    infomsg +=" ,返回消息时长:" + "%.06f"%(time.time()-self.usetime) + 's'
                    GAlogging.info(self.ip_port + infomsg)
                except Exception as e:
                    GAlogging.error(self.ip_port + str(e))
                    GAlogging.error(self.ip_port + 'ga.ini 文件有错误')    
                return True
            else:
                GAlogging.warning(self.ip_port + '没有 ga.ini 文件')
        return False
    
    def response_base(self, statuscode, header, body): 
        # 返回http响应信息 return False 显示错误信息
        msg = '\n'
        msg += ' statuscode=%d'%statuscode + '\n'
        msg += ' {}'.format(header) + '\n'
        msg += ' {}'.format(body) 
        try:
            self.send_response_only(statuscode)
        except Exception as e:
            errormsg = ' Send statuscode happen except:' + str(e) + msg
            GAlogging.error(self.ip_port + errormsg)            
            return False
        for k, v in header.items():
            try:
                self.send_header(k, v)
            except Exception as e:
                errormsg = ' Send header happen except:' + str(e) + msg
                GAlogging.error(self.ip_port + errormsg)            
                return False                    
        try:
            self.end_headers()
        except Exception as e:
            errormsg = ' end_headers happen except:' + str(e) + msg
            GAlogging.error(self.ip_port + errormsg)            
            return False     
        if body:
            try:
                body_bytes = body.encode('utf-8')
                self.wfile.write(body_bytes)
            except Exception as e:
                errormsg = ' Send body happen except:' + str(e) + msg
                GAlogging.error(self.ip_port + errormsg)            
                return False     
        return True
        
    def response_StatusObject(self, ID):
        """
        功能：服务器返回200 OK ,StatusCode="0"
        :param ID:    ID
        return
            True ：回复正常
        """   
        # 如果有ga.ini文件，根据ini文件内容回复消息
        if self.response_useinifile():
            return
        # 1，组包 body
        StatusCode = "0"
        StatusString = "OK"
        LocalTime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        content_dict = {
            "ResponseStatusObject": {
                "Id": ID,
                "RequestURL": self.RequestURL,
                "StatusCode": StatusCode,
                "StatusString": StatusString,
                "LocalTime": LocalTime
            }
        }
        content_str = json.dumps(content_dict)
        content_len = len(content_str)
        # 2，组包 header
        header = {}
        #header["Expires"] = '0'
        header["Content-Type"] = "application/VIID+JSON" #"application/json;charset=UTF-8"
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        header["Date"] = time.strftime(GMT_FORMAT, time.localtime(time.time()))
        header["Connection"] = "close" 
        header["Content-Length"] = str(content_len)
        infomsg = "200 OK" + " ,ID:" + ID
        infomsg +=" ,RequestURL:" + self.RequestURL
        infomsg +=" ,返回消息时长:" + "%.06f"%(time.time()-self.usetime) + 's'
        # 3，回复消息
        if self.response_base(200, header, content_str):
            GAlogging.info(self.ip_port + "回复: " + infomsg)
            return True
        else:
            GAlogging.error(self.ip_port + "没有正确回复: " + infomsg)
        return    
    
    def response_Create(self, IDs):
        """
        功能：服务器返回200 OK ,StatusCode="0"
        :param IDs:    IDs多个ID
        :return: 
            True ：回复正常            
        """   
        # 如果有ga.ini文件，根据ini文件内容回复消息
        if self.response_useinifile():
            return
        # 1，组包 body
        StatusCode = "0"
        StatusString = "OK"        
        LocalTime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        content_dict = {
            "ResponseStatusListObject":{
                "ResponseStatusObject": []
            }
        }        
        value = content_dict["ResponseStatusListObject"]["ResponseStatusObject"]  
        for id in IDs:
            value.append({"RequestURL": self.RequestURL, "StatusCode":StatusCode, "StatusString":StatusString, 'Id':id, "LocalTime":LocalTime})
        content_str = json.dumps(content_dict)
        content_len = len(content_str)
        # 2，组包 header
        header = {}
        header["Content-Type"] = "application/VIID+JSON" 
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        header["Date"] = time.strftime(GMT_FORMAT, time.localtime(time.time()))
        header["Connection"] = "close" 
        header["Content-Length"] = str(content_len)
        infomsg = "200 OK ,IDs:{}".format(IDs)
        infomsg +=" ,RequestURL:%s"%self.RequestURL
        infomsg +=" ,返回消息时长:%.06f"%(time.time()-self.usetime) + 's'
        # 3，回复消息
        if self.response_base(200, header, content_str):
            GAlogging.info(self.ip_port + "回复: " + infomsg)
            return True
        else:
            GAlogging.error(self.ip_port + "没有正确回复: " + infomsg)
        return
        
    def response_200(self, IDs, Reason, StatusCode):
        """
        功能：返回200
        :param IDs:    IDs多个ID
        :param Reason:      原因
        :param StatusCode:  StatusCode
            O-OK， 正常
            1-OtherError，其他未知错误
            2-Device Busy，设备忙
            3-Device Error，设备错
            4-Invalid Operation，无效操作
            5-Invalid XML Format，XML格式无效
            6-Invalid XML Content，XML内容无效
            7-Invalid JSON Format，JSON格式无效
            8-Invalid JSON Content，JSON内容无效
            9-Reboot，系统重启中，以附录B中类型定义为准
        """
        # 如果有ga.ini文件，根据ini文件内容回复消息
        if self.response_useinifile():
            return
        # 1，组包 body
        status_data = {"0":"OK", '1':"OtherError", "2":"Device Busy", "3":"Device Error", \
                        "4":"Invalid Operation", "5":"Invalid XML Format", "6":"Invalid XML Content", \
                        "7":"Invalid JSON Format", "8":"Invalid JSON Content", "9":"Reboot"}
        StatusString = status_data.get(StatusCode)  
        if StatusString == None:
            GAlogging.error(self.ip_port + "StatusCode=%s, error"%StatusCode)
            return
        LocalTime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        content_dict = {
            "ResponseStatusListObject":{
                "ResponseStatusObject": []
            }
        }        
        value = content_dict["ResponseStatusListObject"]["ResponseStatusObject"]  
        for id in IDs:
            value.append({"RequestURL": self.RequestURL, "StatusCode":StatusCode, "StatusString":StatusString, 'Id':id, "LocalTime":LocalTime})
        content_str = json.dumps(content_dict)
        content_len = len(content_str)
        # 2，组包 header
        header = {}
        header["Content-Type"] = "application/VIID+JSON" 
        header["Reason-Phrase"] = Reason 
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        header["Date"] = time.strftime(GMT_FORMAT, time.localtime(time.time()))
        header["Connection"] = "close" 
        header["Content-Length"] = str(content_len)
        infomsg = " StatusCode:{}, StatusString:{}, Reason:{}, RequestURL:{}".format(StatusCode, StatusString, Reason, self.RequestURL)
        infomsg += "\n IDs:{}".format(IDs)
        infomsg += "\n 返回消息时长:%.06f"%(time.time()-self.usetime) + 's'
        # 3，回复消息
        if self.response_base(200, header, content_str):
            if StatusCode == '0':
                GAlogging.info(self.ip_port + "回复: 返回正常 200 " + infomsg)
            else:
                GAlogging.error(self.ip_port + "回复: 返回错误 200 " + infomsg)
            return True
        else:
            GAlogging.error(self.ip_port + "没有正确回复: 200 " + infomsg)
        return
        
    def response_401(self, Reason):
        """
        功能：返回401鉴权挑战
        :param Reason: 原因
        """        
        # 1， 获得pc 的ip
        try:
            ip = ''
            s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            s.connect(('8.8.8.8', 80))
            ip = s.getsockname()[0]
            s.close()    
        except:
            pass        
        if ip:
            realmstr = '"{}"'.format(ip)        
        else:        
            realmstr = '"pmplatform"'
        # 2, 获得nonce
        nonce = self.get_device_nonce()
        if nonce == None:
            nonce = self.create_nonce()   
            self.set_device_nonce(nonce) # 保存
            GAlogging.info(self.ip_port + ' 随机生成nonce:%s'%nonce)
        noncestr = '"' + nonce + '"'
        qopstr = '"auth"'
        stalestr = '"true"'
        #auth = 'Digest realm=' + realmstr + ',qop=' + qopstr + ',nonce=' + noncestr + ',stale=' + stalestr
        auth = 'Digest realm=' + realmstr + ',qop=' + qopstr + ',nonce=' + noncestr
               
        header = {}
        header["Content-Type"] = "application/VIID+JSON" 
        header["Reason-Phrase"] = Reason
        header["WWW-Authenticate"] = auth
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        header["Date"] = time.strftime(GMT_FORMAT, time.localtime(time.time()))
        header["Connection"] = "close" 
        header["Content-Length"] = "0"
        infomsg = "401鉴权挑战" +" ,Reason:" + Reason
        if self.response_base(401, header, ""):  
            GAlogging.info(self.ip_port + "回复: " + infomsg)
        else:
            GAlogging.error(self.ip_port + "没有正确回复: " + infomsg)
        return True

    def response_400(self, Reason):
        """
        功能：返回400
        :param Reason: 原因
        """        
        header = {}
        header["Content-Type"] = "application/VIID+JSON" 
        header["Reason-Phrase"] = Reason
        GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
        header["Date"] = time.strftime(GMT_FORMAT, time.localtime(time.time()))
        header["Connection"] = "close" 
        header["Content-Length"] = "0"
        infomsg = " 回复400" + " ,Reason:" + Reason
        if self.response_base(400, header, ""):
            GAlogging.info(self.ip_port + "回复: " + infomsg)
        else:
            GAlogging.error(self.ip_port + "没有正确回复: " + infomsg)
        return
        
    def parseid_fromxxxObject(self, pictype, Object_dict):
        """ 
        功能：获得 DeviceID, SourceID, 根据pictype 返回FaceID 或 PersonID ...
        pictype: FaceObject, PersonObject ...
        Object_dict: FaceObject, PersonObject ...
        return -1 error， 并回复200 + 错误的code
        # MotorVehicleListObject :{ MotorVehicleObject :[{}, {}]}   获取ID信息，车辆信息
        # example: "InfoKind": 1 自动采集， "PlateNo": "京NR5659" 车牌， "PlateColor": "5" 颜色, ...
        """
        DeviceID = Object_dict.get('DeviceID') 
        if DeviceID == None:
            others = "not found DeviceID!"
            self.response_200([''], others, "8")
            return -1 
        self.DeviceID = DeviceID
        self.DeviceIDs.append(DeviceID)    
        self.SourceID = Object_dict.get('SourceID')
        if self.SourceID == None:            
            others = "not found SourceID!"
            self.response_200([self.DeviceID], others, "8")
            return -1
        self.SourceIDs.append(self.SourceID)
        if pictype == 'FaceObject':
            self.FaceID = Object_dict.get("FaceID")
            if self.FaceID == None: 
                others = "not found FaceID in FaceObject!"
                self.response_200([self.DeviceID], others, "8")
                return -1
            self.FaceIDs.append(self.FaceID)
        elif pictype == 'PersonObject':
            self.PersonID = Object_dict.get("PersonID")
            if self.PersonID == None: 
                others = "not found PersonID in PersonObject!"
                self.response_200([self.DeviceID], others, "8")
                return -1
            self.PersonIDs.append(self.PersonID)
        elif pictype == 'MotorVehicleObject':
            self.MotorVehicleID = Object_dict.get("MotorVehicleID")
            if self.MotorVehicleID == None: 
                others = "not found MotorVehicleID in MotorVehicleObject!"
                self.response_200([self.DeviceID], others, "8")
                return -1
            self.MotorVehicleIDs.append(self.MotorVehicleID)
        elif pictype == 'NonMotorVehicleObject':
            self.NonMotorVehicleID = Object_dict.get("NonMotorVehicleID")
            if self.NonMotorVehicleID == None: 
                others = "not found NonMotorVehicleID in NonMotorVehicleObject!"
                self.response_200([self.DeviceID], others, "8")
                return -1
            self.NonMotorVehicleIDs.append(self.NonMotorVehicleID)
        return 0
    
    def parseid_fromSubImageInfoObject(self, SubImageInfoObject):  
        """
        功能： 获得 FileFormat, Shottime, Type ，ImageID
        SubImageInfoObject: SubImageInfoObject
        return -1 错误，并回复200 + 错误的code
        # "SubImageList": { "SubImageInfoObject": [ {ImageID: ,  Shottime: , Type: , Data: } , {} ]
        """
        FileFormat = SubImageInfoObject.get('FileFormat')  
        if FileFormat == None:
            others = "not found FileFormat in SubImageInfoObject"
            self.response_200([''], others, "8")
            return -1  
        self.ImageID = SubImageInfoObject.get("ImageID")
        if self.ImageID == None:
            others = "not found ImageID in SubImageInfoObject"
            self.response_200([''], others, "8")
            return -1
        ShotTime = SubImageInfoObject.get("ShotTime")
        if ShotTime == None:
            others = "not found ShotTime in SubImageInfoObject"
            self.response_200([''], others, "8")
            return -1     
        smalljpg_type = SubImageInfoObject.get("Type")
        if smalljpg_type == None:
            others = "not found Type in SubImageInfoObject"
            self.response_200([''], others, "8")
            return -1   
        return FileFormat, ShotTime, smalljpg_type
        
    def process_xxxObject(self, pictype, picpath, xxxObject):  
        """
        功能：从FaceObject: [{}, {}] 获取图片信息， 保存图片和json数据
        pictype: 'PersonObject' , 'FaceObject'  ,'MotorVehicleObject', 'NonMotorVehicleObject'
        picpath: 保存图片和json的目录
        xxxObject: FaceObject, PersonObject...
        return ： error -1，并回复200 + 错误的code
        """
        ip = self.client_address[0]
        for Object_dict in xxxObject:
            # 1, 得到SourceID, DeviceID, FaceID, ...
            ret = self.parseid_fromxxxObject(pictype, Object_dict)
            if ret == -1:
                return -1
            # 2, SubImageList列表
            SubImageList = Object_dict.get("SubImageList")
            if SubImageList == None:
                others = "not found SubImageList in " + pictype
                self.response_200([self.DeviceID], others, "8")
                return -1            
            SubImageInfoObject_list = SubImageList.get("SubImageInfoObject")   
            if SubImageInfoObject_list == None:
                others = "not found SubImageInfoObject in SubImageList"
                self.response_200([self.DeviceID], others, "8")
                return -1  
            if not isinstance(SubImageInfoObject_list, list):
                others = "SubImageInfoObject is not list"
                self.response_200([self.DeviceID], others, "8")
                return -1 
            self.numSubImageInfoObject += len(SubImageInfoObject_list) # 图片总数量
            for SubImageInfoObject_dict in SubImageInfoObject_list:   
                # 3, 解析 SubImageInfoObject 得到 ImageID , Shottime
                ret = self.parseid_fromSubImageInfoObject(SubImageInfoObject_dict)
                if ret == -1:
                    return -1
                FileFormat, ShotTime, smalljpg_type = ret
                # 4, 根据type 保存图片
                """
                1	01	车辆大图
                2	02	车牌彩色小图
                3	03	车牌二值化图
                4	04	驾驶员面部特征图
                5	05	副驾驶面部特征图
                6	06	车标
                7	07	违章合成图
                8	08	过车合成图
                9	09	车辆特写图
                10	10	人员图
                11	11	人脸图
                12	12	非机动车图
                13	13	物品图
                14	14	场景图
                15	100	一般图片
                """
                small_image_file = ''
                define_jpgtype = {"01":"车辆大图", "02":"车牌彩色小图", "03":"车牌二值化图", "04":"驾驶员面部特征图", \
                                    "05":"副驾驶面部特征图", "06":"车标", "07":"违章合成图", "08":"过车合成图", \
                                    "09":"车辆特写图", "10":"人员图", "11":"人脸图", "12":"非机动车图", \
                                    "13":"物品图", "14":"场景图", "100":"一般图片"}
                # 文件路径  
                if smalljpg_type not in define_jpgtype.keys():
                    others = "Type=%s error!"%smalljpg_type
                    self.response_200([self.DeviceID], others, "8")
                    return -1                 
                jpgtype = define_jpgtype.get(smalljpg_type)
                jpgtype_num = int(smalljpg_type)
                jpglogmsg = ''
                if pictype == 'FaceObject':  
                    if jpgtype_num < 100:
                        self.facePicNums[jpgtype_num-1] += 1
                    else:
                        self.facePicNums[14] += 1
                    jpglogmsg = '\n命名： FaceID = %s'%self.FaceID 
                    jpglogmsg += ', ImageID = %s'%self.ImageID
                    jpglogmsg += ', Shottime = %s, '%ShotTime + pictype + ' Type = %s'%smalljpg_type
                    small_image_file = "{}_{}_{}_{}_{}_{}.jpg".format(ip, self.FaceID, self.ImageID, ShotTime, pictype, jpgtype)    
                elif pictype == 'PersonObject':   
                    if jpgtype_num < 100:
                        self.personPicNums[jpgtype_num-1] += 1
                    else:
                        self.personPicNums[14] += 1       
                    jpglogmsg = '\n命名： PersonID = %s'%self.PersonID
                    jpglogmsg += ', ImageID = %s'%self.ImageID
                    jpglogmsg += ', Shottime = %s, '%ShotTime + pictype + ' Type = %s'%smalljpg_type
                    small_image_file = "{}_{}_{}_{}_{}_{}.jpg".format(ip, self.PersonID, self.ImageID, ShotTime, pictype, jpgtype)
                elif pictype == 'MotorVehicleObject':
                    if jpgtype_num < 100:
                        self.motorPicNums[jpgtype_num-1] += 1
                    else:
                        self.motorPicNums[14] += 1     
                    jpglogmsg = '\n命名： MotorVehicleID = %s'%self.MotorVehicleID 
                    jpglogmsg += ', ImageID = %s'%self.ImageID
                    jpglogmsg += ', Shottime = %s, '%ShotTime + pictype + ' Type = %s'%smalljpg_type
                    small_image_file = "{}_{}_{}_{}_{}_{}.jpg".format(ip, self.MotorVehicleID, self.ImageID, ShotTime, pictype, jpgtype)   
                elif pictype == 'NonMotorVehicleObject':
                    if jpgtype_num < 100:
                        self.nonmotorPicNums[jpgtype_num-1] += 1
                    else:
                        self.nonmotorPicNums[14] += 1  
                    jpglogmsg = '\n命名： NonMotorVehicleID = %s'%self.NonMotorVehicleID 
                    jpglogmsg += ', ImageID = %s'%self.ImageID
                    jpglogmsg += ', Shottime = %s, '%ShotTime + pictype + ' Type = %s'%smalljpg_type 
                    small_image_file = "{}_{}_{}_{}_{}_{}.jpg".format(ip, self.NonMotorVehicleID, self.ImageID, ShotTime, pictype, jpgtype) 
                image_file = os.path.join(picpath, small_image_file)
                # 5, save json  jpg 
                jsonlogmsg = ''
                if save_json == 1:                        
                    if 1:
                        with open(image_file[:-4]+'.json', 'w', encoding='utf8') as f:
                            json.dump(SubImageInfoObject_dict, f, ensure_ascii=False,indent=2)
                    else:
                        json_str = json.dumps(SubImageInfoObject_dict)
                        try:
                            with open(image_file[:-4]+'.json', 'w') as f:
                                f.write(json_str)
                        except Exception as e:
                            GAlogging.error(self.ip_port + '写{},出现异常:'.format(image_file[:-4]+'.json') + str(e))
                    if pictype == 'FaceObject':
                        jsonlogmsg += "\njson：{}".format(image_file[:-4]+'.json')
                    elif pictype == 'PersonObject':
                        jsonlogmsg += "\njson：{}".format(image_file[:-4]+'.json')
                    elif pictype == 'MotorVehicleObject':
                        jsonlogmsg += "\njson：{}".format(image_file[:-4]+'.json')
                    elif pictype == 'NonMotorVehicleObject':
                        jsonlogmsg += "\njson：{}".format(image_file[:-4]+'.json') 
                if loglevel > 0:
                    msg = " picture:{}".format(image_file) + jsonlogmsg + jpglogmsg
                    for k, v in SubImageInfoObject_dict.items():
                        if k == 'Data':
                            pass
                        else:
                            msg += '\n {}: {}'.format(k, v)
                    GAlogging.info(self.ip_port + msg)
                if os.path.isfile(image_file):
                    others = "有重名图片:{}".format(image_file)
                    GAlogging.warning(self.ip_port + others)
                    self.repeatpicsum += 1
                    #self.response_200([self.DeviceID], others, "1")
                    #return -1                 
                Data_str = SubImageInfoObject_dict.get("Data")
                if Data_str == None:
                    others = "not found Data in SubImageInfoObject"
                    self.response_200([self.DeviceID], others, "8")
                    return -1
                try:
                    jpg = base64.b64decode(Data_str.encode("utf-8"))
                except Exception as e:
                    GAlogging.error(self.ip_port + "Exception is：" + str(e))               
                    others = "base64 decode error" 
                    self.response_200([self.DeviceID], others, "1")
                    return -1
                if len(jpg) == 0:
                    self.zeropicsum += 1
                    self.savedata(image_file, jpg)
                else:
                    if save_jpg == 1:
                        self.savedata(image_file, jpg) 
                    if self.check_jpgformat(image_file, jpg) == False:
                        others = "jpg format error"
                        self.response_200([self.DeviceID], others, "6")
                        return -1
        return 0
     
    def process_xxxListObject(self, picpath, Object_dict):
        """
        功能：解析Image, VideoSlice, File 中人脸，人员, 机动车， 非机动车
        picpath: 保存图片和json的目录
        return False 错误，并回复200 + 错误的code，  正确返回True 
        "ImageListObject": {    "Image": [{}, {}]   }
        """
        FaceList = Object_dict.get("FaceList")
        if FaceList:
            pictype = "FaceObject"
            FaceObject = FaceList.get("FaceObject")
            if FaceObject == None:
                others = "not found FaceObject in FaceList"
                self.response_200([''], others, "8")
                return False
            if not isinstance(FaceObject, list):                  
                others = "FaceObject is not list"
                self.response_200([''], others, "8")
                return False                                     
            ret = self.process_xxxObject(pictype, picpath, FaceObject)
            if ret == -1:
                return False     
                
        PersonList = Object_dict.get("PersonList")
        if PersonList:
            pictype = "PersonObject"
            PersonObject = PersonList.get("PersonObject")
            if PersonObject == None:
                others = "not found PersonObject in PersonList"
                self.response_200([''], others, "8")
                return False
            if not isinstance(PersonObject, list):   
                others = "PersonObject is not list"
                self.response_200([''], others, "8")
                return False                                     
            ret = self.process_xxxObject(pictype, picpath, PersonObject)
            if ret == -1:
                return False                                                           

        MotorVehicleList = Object_dict.get("MotorVehicleList")
        if MotorVehicleList:
            pictype = "MotorVehicleObject"
            MotorVehicleObject = MotorVehicleList.get("MotorVehicleObject")
            if MotorVehicleObject == None:
                others = "not found MotorVehicleObject in MotorVehicleList"
                self.response_200([''], others, "8")
                return False
            if not isinstance(MotorVehicleObject, list): 
                others = "MotorVehicleObject is not list"
                self.response_200([''], others, "8")
                return False                                       
            ret = self.process_xxxObject(pictype, picpath, MotorVehicleObject)
            if ret == -1:
                return False                                                           

        NonMotorVehicleList = Object_dict.get("NonMotorVehicleList")
        if NonMotorVehicleList:
            pictype = "NonMotorVehicleObject"
            NonMotorVehicleObject = NonMotorVehicleList.get("NonMotorVehicleObject")
            if NonMotorVehicleObject == None:
                others = "not found NonMotorVehicleObject in NonMotorVehicleList"
                self.response_200([''], others, "8")
                return False
            if not isinstance(NonMotorVehicleObject, list):  
                others = "NonMotorVehicleObject is not list"
                self.response_200([''], others, "8")
                return False                                      
            ret = self.process_xxxObject(pictype, picpath, NonMotorVehicleObject)
            if ret == -1:
                return False                                                           
        return True
            
    def init_param(self):
        #self.now = datetime.datetime.now()      # 记录接收时间
        self.DeviceID = ''
        self.DeviceIDs = []
        self.FaceID = ''
        self.FaceIDs = []
        self.PersonID = ''
        self.PersonIDs = []
        self.FileID = ''
        self.FileIDs = []        
        self.VideoID = ''
        self.VideoIDs = []
        self.ImageID = ''
        self.ImageIDs = []
        self.SourceID = ''
        self.SourceIDs = []
        self.MotorVehicleID = ''
        self.MotorVehicleIDs = []
        self.NonMotorVehicleID = ""
        self.NonMotorVehicleIDs = []
        self.numSubImageInfoObject = 0  # 图片总数量
        self.imgbigPicNums = 0  #image 大图
        self.facePicNums = [0]*15    #FaceObject 图
        self.personPicNums = [0]*15   #person小图
        self.motorPicNums = [0]*15   #机动车图
        self.nonmotorPicNums = [0]*15   #非机动车小图
        self.FileNums = 0  # 文件数量        
        self.VideoNums = 0 # 录像数量
        self.errpicsum = 0 # 错误图片数量0
        self.zeropicsum = 0 # 图片大小为0的数量0
        self.repeatpicsum = 0 # 重复名称图片数 0
        self.usetime = time.time()
                          
    def do_GET(self):   
        self.init_param()
        self.ip_port = "{} {} : ".format(self.client_address, self.requestline)
        if "GET /VIID/System/Time" in self.requestline:
            GAlogging.info(self.ip_port + "*** 校时 ***" + "\n{}".format(self.headers))
            VIIDServerID = self.headers.get("User-Identify", "0")
            LocalTime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
            content_dict =  {
                "SystemTimeObject": {
                    "LocalTime": LocalTime,
                    "RequestURL": "/VIID/System/Time",
                    "TimeMode": 1,
                    "TimeZone": "Etc/GMT-8",
                    "VIIDServerID": VIIDServerID
                }
            }
            content_str = json.dumps(content_dict)
            content_len = len(content_str)
            header = {}
            header["Content-Type"] = "application/VIID+JSON"
            GMT_FORMAT = '%a, %d %b %Y %H:%M:%S GMT'
            header["Date"] = time.strftime(GMT_FORMAT, time.localtime(time.time()))
            header["Connection"] = "close"
            header["Content-Length"] = str(content_len)
            infomsg = content_str
            if self.response_base(200, header, content_str):
                GAlogging.info(self.ip_port + "回复: " + infomsg)
            else:
                GAlogging.error(self.ip_port + "没有正确回复: " + infomsg)
        elif "GET /VIID/Images" in self.requestline:
            GAlogging.info(self.ip_port + "*** 查询图像 ***")
        elif "GET /VIID/VideoSlices" in self.requestline:
            GAlogging.info(self.ip_port + "*** 查询视频片段 ***")
        elif "GET /VIID/APEs" in self.requestline:
            GAlogging.info(self.ip_port + "*** 查询采集设备 ***")
        else:
            GAlogging.info(self.ip_port + "*** 其他GET消息 ***")
        
    def getThreads(self):
        try:
            threadNumsLock.acquire()     
            msg = "GA接收消息线程\n"
            msg += 'before :{}个线程,[{}]'.format(len(allThreads), allThreads)
            aliveThreads=[]
            for curthread in allThreads:
                if curthread.is_alive():
                    aliveThreads.append(curthread)
            allThreads.clear()
            allThreads.extend(aliveThreads)
            if threading.current_thread() not in aliveThreads:
                allThreads.append(threading.current_thread())
            msg += '\nafter :{}个线程,[{}]'.format(len(allThreads),allThreads)
            GAlogging.info(self.ip_port + msg)
            if threadNumsLock.locked():
                threadNumsLock.release()  
        except Exception as e:
            GAlogging.error(self.ip_port + 'except: ' + str(e))
            
    def read_httpContent(self):
        """
        功能：读取 http的body
        # return 
        None： 错误，并回复200 + 错误的code， 
        json_dict：正确，返回实际值
        """
        cont_length = self.headers.get("Content-Length")
        if cont_length == None:
            others = "not found Content-Length" 
            self.response_200([''], others, "1")
            return None
        try:
            content_length = int(cont_length)
        except Exception as e:
            GAlogging.error(self.ip_port + "Exception: " + str(e) + '\n' + str(self.headers))
            others = "content_length=%s is not digital!"%cont_length
            self.response_200([''], others, "1")
            return None
        if content_length < 0:
            others = 'Content-Length=%d is error'%content_length                
            self.response_200([''], others, "1")
            return None
        try:
            json_bytes = self.rfile.read(content_length)  
        except Exception as e:
            GAlogging.error(self.ip_port + "Exception: " + str(e))
            others = "read content happen except : " + str(e)             
            self.response_200([''], others, "1")
            return None
        json_len = len(json_bytes)
        if json_len != content_length:
            others = "json_len[%d] != content_length[%d]"%(json_len,content_length)
            self.response_200([''], others, "1")
            try:
                b = self.requestline.split(' ')
                c = b[1].split('/')
                nowtime = datetime.datetime.now()
                ntime = "{}{}{}_{}{}{}_{}".format(nowtime.year,nowtime.month,nowtime.day,nowtime.hour,nowtime.minute,nowtime.second,nowtime.microsecond)
                errorfile = "lengtherror_{}_{}.txt".format(c[-1],ntime)
            except:        
                nowtime = datetime.datetime.now()
                ntime = "{}{}{}_{}{}{}_{}".format(nowtime.year,nowtime.month,nowtime.day,nowtime.hour,nowtime.minute,nowtime.second,nowtime.microsecond)
                errorfile = "lengtherror_{}.txt".format(ntime)
            with open(errorfile, 'wb') as f:
                f.write(json_bytes)
                GAlogging.error(self.ip_port + " lengtherror : " + errorfile) 
            return None
        try:
            json_str = json_bytes.decode('utf-8')
        except Exception as e:
            GAlogging.error(self.ip_port + "Exception: " +str(e))            
            others = "decode utf-8 error!"             
            self.response_200([''], others, "1")
            try:
                b = self.requestline.split(' ')
                c = b[1].split('/')
                nowtime = datetime.datetime.now()
                ntime = "{}{}{}_{}{}{}_{}".format(nowtime.year,nowtime.month,nowtime.day,nowtime.hour,nowtime.minute,nowtime.second,nowtime.microsecond)
                errorfile = "except_utf8_{}_{}.txt".format(c[-1],ntime)
            except:        
                nowtime = datetime.datetime.now()
                ntime = "{}{}{}_{}{}{}_{}".format(nowtime.year,nowtime.month,nowtime.day,nowtime.hour,nowtime.minute,nowtime.second,nowtime.microsecond)
                errorfile = "except_utf8_{}.txt".format(ntime)
            with open(errorfile, 'wb') as f:
                f.write(json_bytes)
                GAlogging.error(self.ip_port + " decode utf-8 except : " + errorfile) 
            return None
        try:
            # decode 数据成 json格式后返回
            json_dict = json.loads(json_str)
        except Exception as e:
            GAlogging.error(self.ip_port + "Exception: " +str(e))
            others = "json format error!"             
            self.response_200([''], others, "7")
            try:
                b = self.requestline.split(' ')
                c = b[1].split('/')
                nowtime = datetime.datetime.now()
                ntime = "{}{}{}_{}{}{}_{}".format(nowtime.year,nowtime.month,nowtime.day,nowtime.hour,nowtime.minute,nowtime.second,nowtime.microsecond)
                errorfile = "except_json_{}_{}.txt".format(c[-1],ntime)
            except:        
                nowtime = datetime.datetime.now()
                ntime = "{}{}{}_{}{}{}_{}".format(nowtime.year,nowtime.month,nowtime.day,nowtime.hour,nowtime.minute,nowtime.second,nowtime.microsecond)
                errorfile = "except_json_{}.txt".format(ntime)
            with open(errorfile, 'wb') as f:
                f.write(json_bytes)
                GAlogging.error(self.ip_port + " json format except : " + errorfile) 
            return None  
        return json_dict 
        
    def savegadb(self,json_dict):       
        if use_sqlite3 == 1:
            galibLock.acquire()
            try: 
                localtime = time.strftime("%Y%m%d_%H%M%S", time.localtime(server_runtime[0]))
                dbname = 'gahttps_{}.db'.format(localtime)
                gapic_lib = gadb_sqlite.GAPICLIB(dbname=dbname)
                gadb_sqlite.insert_data(json_dict, gapic_lib)
                gapic_lib.save()
                gapic_lib.close()
            except Exception as e:
                GAlogging.error(self.ip_port + str(e)) 
            if galibLock.locked():
                galibLock.release()

    # 获得 是否有设备ip 信息
    def get_device_ip(self):        
        ip = self.client_address[0]
        resultLock.acquire()
        ret = device_registerinfo.get(ip)
        if resultLock.locked():
            resultLock.release()
        return ret
        
    # 删除 ip的注册时间，nonce , 注销时间，刷新注册时间，result
    def del_device_ip(self): 
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip):            
            del (device_registerinfo[ip])
        if resultLock.locked():
            resultLock.release()
    
    # 获得 nonce    
    def get_device_nonce(self):      
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip) == None:
            ret = None       
        else:
            ret = device_registerinfo[ip].get('nonce')
        if resultLock.locked():
            resultLock.release()
        return ret
        
    # 设置 nonce    
    def set_device_nonce(self, nonce):   
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip):
            device_registerinfo[ip]['nonce'] = nonce
        else:
            device_registerinfo[ip] = {}
            device_registerinfo[ip]['nonce'] = nonce    
        if resultLock.locked():
            resultLock.release()
             
    # 删除 nonce
    def del_device_nonce(self):    
        ip = self.client_address[0]        
        resultLock.acquire()
        if device_registerinfo.get(ip):
            if device_registerinfo[ip].get('nonce'):
                del (device_registerinfo[ip]['nonce'])
        if resultLock.locked():
            resultLock.release()
                
    # 获得 注册时间 registertime
    def get_device_registertime(self):       
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip) == None:
            others = "%s not register"%ip
            GAlogging.warning(self.ip_port + others)
            ret = None               
        else:
            ret = device_registerinfo[ip].get('registertime')
        if resultLock.locked():
            resultLock.release()
        return ret
        
    # 设置 注册时间 registertime
    def set_device_registertime(self, registertime):   
        ip = self.client_address[0]
        resultLock.acquire() 
        if device_registerinfo.get(ip):
            device_registerinfo[ip]['registertime'] = registertime
        else:
            device_registerinfo[ip] = {}
            device_registerinfo[ip]['registertime'] = registertime
        if resultLock.locked():
            resultLock.release()
    
    # 删除 注册时间 registertime
    def del_device_registertime(self):    
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip):
            if device_registerinfo[ip].get('registertime'):
                del (device_registerinfo[ip]['registertime'])
        if resultLock.locked():
            resultLock.release()
                
    # 获得 注册时间 record_registertime
    def get_device_recordregtime(self):        
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip) == None:
            others = "%s not register"%ip
            GAlogging.warning(self.ip_port + others)
            ret = None
        else:
            ret = device_registerinfo[ip].get('record_registertime')
        if resultLock.locked():
            resultLock.release()    
        return ret 
        
    # 设置 记录 注册时间列表 record_registertime
    def set_device_recordregtime(self, record_registertime):
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip):
            if device_registerinfo[ip].get('record_registertime'):
                device_registerinfo[ip]['record_registertime'].append(record_registertime)
            else:
                device_registerinfo[ip]['record_registertime'] = [record_registertime]
        else:
            device_registerinfo[ip] = {}
            device_registerinfo[ip]['record_registertime'] = [record_registertime]
        if resultLock.locked():
            resultLock.release()    
            
    # 获得 刷新注册时间 refresh_registertime
    def get_device_refreshregtime(self):        
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip) == None:
            others = "%s not register"%ip
            GAlogging.warning(self.ip_port + others)
            ret = None
        else:
            ret = device_registerinfo[ip].get('refresh_registertime')
        if resultLock.locked():
            resultLock.release()    
        return ret

    # 设置 刷新注册时间 refresh_registertime
    def set_device_refreshregtime(self, refresh_registertime):
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip):
            if device_registerinfo[ip].get('refresh_registertime'):
                device_registerinfo[ip]['refresh_registertime'].append(refresh_registertime)
            else:
                device_registerinfo[ip]['refresh_registertime'] = [refresh_registertime]
        else:
            device_registerinfo[ip] = {}
            device_registerinfo[ip]['refresh_registertime'] = [refresh_registertime]
        if resultLock.locked():
            resultLock.release()    
            
    # 设置 注销时间 unregistertime
    def set_device_unregistertime(self, unregistertime):
        ip = self.client_address[0]
        resultLock.acquire()
        if device_registerinfo.get(ip):
            if device_registerinfo[ip].get('unregistertime'):
                device_registerinfo[ip]['unregistertime'].append(unregistertime)
            else:
                device_registerinfo[ip]['unregistertime'] = [unregistertime]
        else:
            device_registerinfo[ip] = {}
            device_registerinfo[ip]['unregistertime'] = [unregistertime]
        if resultLock.locked():
            resultLock.release()            
        
    # 保存图片数量统计信息 到全局变量中    
    def set_device_result(self):     
        ip = self.client_address[0]        
        # 1， 检查ip
        device = device_registerinfo.get(ip)
        if device == None:  
            others = "%s not register"%ip
            GAlogging.warning(self.ip_port + others)
            return
        # 2， 检查 result
        result = device.get('result')
        if result == None: 
            # 没有图片接收信息，初始化
            device_registerinfo[ip]['result'] = {}
            if "/VIID/Images" == self.RequestURL:
                device_registerinfo[ip]['result'][self.RequestURL] = [1, self.numSubImageInfoObject, \
                    self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                    self.imgbigPicNums, self.errpicsum, self.zeropicsum, self.repeatpicsum]
            elif "/VIID/Files" == self.RequestURL:
                device_registerinfo[ip]['result'][self.RequestURL] = [1, self.numSubImageInfoObject, \
                    self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                    self.FileNums, self.errpicsum, self.zeropicsum, self.repeatpicsum]
            elif "/VIID/VideoSlices" == self.RequestURL:
                device_registerinfo[ip]['result'][self.RequestURL] = [1, self.numSubImageInfoObject, \
                    self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                    self.VideoNums, self.errpicsum, self.zeropicsum, self.repeatpicsum]
            else:
                device_registerinfo[ip]['result'][self.RequestURL] = [1, self.numSubImageInfoObject, \
                    self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                    0, self.errpicsum, self.zeropicsum, self.repeatpicsum]
        else:
            if result.get(self.RequestURL) == None:
                # 没有 self.RequestURL 的信息，初始化     
                if "/VIID/Images" == self.RequestURL:
                    result[self.RequestURL] = [1, self.numSubImageInfoObject, \
                        self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                        self.imgbigPicNums, self.errpicsum, self.zeropicsum, self.repeatpicsum]
                elif "/VIID/Files" == self.RequestURL:
                    result[self.RequestURL] = [1, self.numSubImageInfoObject, \
                        self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                        self.FileNums, self.errpicsum, self.zeropicsum, self.repeatpicsum]
                elif "/VIID/VideoSlices" == self.RequestURL:
                    result[self.RequestURL] = [1, self.numSubImageInfoObject, \
                        self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                        self.VideoNums, self.errpicsum, self.zeropicsum, self.repeatpicsum]
                else:
                    result[self.RequestURL] = [1, self.numSubImageInfoObject, \
                        self.facePicNums, self.personPicNums, self.motorPicNums, self.nonmotorPicNums, \
                        0, self.errpicsum, self.zeropicsum, self.repeatpicsum] 
            else:
                # 更新 数量
                result[self.RequestURL][0] += 1
                result[self.RequestURL][1] += self.numSubImageInfoObject
                for x in range(15):
                    result[self.RequestURL][2][x] += self.facePicNums[x]
                for x in range(15):
                    result[self.RequestURL][3][x] += self.personPicNums[x]
                for x in range(15):
                    result[self.RequestURL][4][x] += self.motorPicNums[x]
                for x in range(15):
                    result[self.RequestURL][5][x] += self.nonmotorPicNums[x]
                if "/VIID/Images" == self.RequestURL:
                    result[self.RequestURL][6] += self.imgbigPicNums
                elif "/VIID/Files" == self.RequestURL:
                    result[self.RequestURL][6] += self.FileNums
                elif "/VIID/VideoSlices" == self.RequestURL:
                    result[self.RequestURL][6] += self.VideoNums
                else:
                    result[self.RequestURL][6] = 0
                result[self.RequestURL][7] += self.errpicsum
                result[self.RequestURL][8] += self.zeropicsum
                result[self.RequestURL][9] += self.repeatpicsum
        if loglevel > 0:
            self.printids()
            reusltmsg = count_jpgnums(device_registerinfo[ip]['result'][self.RequestURL], self.RequestURL)
            GAlogging.info(self.ip_port + reusltmsg)
        return
        
    def process_register_request(self):
        # 处理注册请求
        ip = self.client_address[0]
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:            
            # 2，检查参数 RegisterObject DeviceID
            RegisterObject = json_dict.get("RegisterObject")
            if RegisterObject == None:
                others = "not found RegisterObject"
                self.response_200([''], others, "8")
                return 
            DeviceID = json_dict["RegisterObject"].get("DeviceID")
            if DeviceID == None:
                others = "not found DeviceID in RegisterObject"
                self.response_200([''], others, "8")
                return                
            self.DeviceID = DeviceID 
            # 3， 检查 Authorization 判断
            digest = self.headers.get("Authorization") 
            if digest == None:
                GAlogging.info(self.ip_port + "没有携带授权信息")          
                self.del_device_registertime() # 删除 注册时间 registertime
                self.del_device_nonce()      
                others = "删除注册时间，nonce"
                GAlogging.info(self.ip_port + others)
                # 4，服务器回复401鉴权挑战 
                self.response_401('Authorization not in Register request')
                return 
            else:
                GAlogging.info(self.ip_port + "***有授权信息***")  
                # 5，判断 ip 是否注册
                if self.get_device_ip() == None:
                    others = "%s not register"%ip
                    self.response_401(others)
                    return    
                # 6，判断 nonce
                nonce = self.get_device_nonce()
                if nonce == None:
                    others = "not found %s nonce"%ip
                    self.response_401(others)
                    return   
                # 7，检查 认证 是否成功，如认证失败 内部返回401 重新认证
                if self.check_Authorization(digest, nonce) == False:
                    return   
                # 8，判断 注册时间
                if self.get_device_registertime(): # 如果有注册时间
                    curtime = time.time()
                    self.set_device_recordregtime(curtime)
                    others = "更新注册时间列表:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime)))
                    GAlogging.info(self.ip_port + others)
                else:   # 没有注册时间
                    curtime = time.time()
                    self.set_device_registertime(curtime)       # 设置注册时间
                    self.set_device_recordregtime(curtime)
                    othersmsg = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime))
                    others = "设置注册时间:{}".format(othersmsg)
                    others += " , 更新注册时间列表:{}".format(othersmsg)
                    GAlogging.info(self.ip_port + others)
                # 9， 响应
                self.response_StatusObject(self.DeviceID)                
                return
            
    def process_unregister_request(self):
        # 处理注销请求
        ip = self.client_address[0]    
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:
            # 2，检查参数 UnRegisterObject DeviceID
            UnRegisterObject = json_dict.get("UnRegisterObject")
            if UnRegisterObject == None:
                others = "not found UnRegisterObject"
                self.response_200([''], others, "8")
                return   
            DeviceID = json_dict["UnRegisterObject"].get("DeviceID")
            if DeviceID == None:
                others = "not found DeviceID in UnRegisterObject"
                self.response_200([''], others, "8")
                return
            self.DeviceID = DeviceID        
            # 3， 检查 Authorization 判断
            digest = self.headers.get("Authorization") 
            if digest == None:
                GAlogging.info(self.ip_port + "没有携带授权信息")                 
                # 4, 服务器回复401鉴权挑战 
                self.response_401('Authorization not in UnRegister request') 
                return
            else:
                GAlogging.info(self.ip_port + "***有授权信息***")    
                # 5，判断 ip 是否注册
                if self.get_device_ip() == None:
                    others = "%s not register"%ip
                    self.response_401(others)
                    return  
                # 6，判断 nonce
                nonce = self.get_device_nonce()
                if nonce == None:
                    others = "not found %s nonce"%ip
                    self.response_401(others)
                    return   
                # 7，检查 认证 是否成功，如认证失败 内部返回401 重新认证
                if self.check_Authorization(digest, nonce) == False:
                    return    
                # 8，更新注销时间
                curtime = time.time()
                self.set_device_unregistertime(curtime) # 设置注销时间
                self.del_device_registertime() # 删除 注册时间 registertime
                self.del_device_nonce()
                others = "更新注销时间:{}".format(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(curtime)))
                others += "删除注册时间，nonce"
                GAlogging.info(self.ip_port + others)
                # 9， 响应
                self.response_StatusObject(self.DeviceID)
                return
              
    def process_keepalive_request(self):    
        # 处理 keepalive 请求            
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:  
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return
            # 3，检查参数 KeepaliveObject DeviceID
            KeepaliveObject = json_dict.get("KeepaliveObject")
            if KeepaliveObject == None:
                others = "not found KeepaliveObject"
                self.response_200([''], others, "8")
                return   
            DeviceID = json_dict["KeepaliveObject"].get("DeviceID")
            if DeviceID == None:
                others = "not found DeviceID in KeepaliveObject"
                self.response_200([''], others, "8")
                return
            self.DeviceID = DeviceID
            # 4， 响应
            self.response_StatusObject(self.DeviceID)
            return          
        
    def process_faces_request(self):    
        # 处理 faces 请求   , call process_xxxObject
        pictype = 'FaceObject'
        picpath = 'GAHttps/face_jpg'
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict: 
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return  
            self.savegadb(json_dict)  
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return 
            # 3，检查参数, FaceListObject FaceObject
            FaceListObject = json_dict.get("FaceListObject")
            if FaceListObject == None:
                others = "not found FaceListObject"
                self.response_200([''], others, "8")
                return   
            FaceObject = json_dict["FaceListObject"].get("FaceObject")
            if FaceObject == None:  
                others = "not found FaceObject in FaceListObject"
                self.response_200([''], others, "8")
                return
            #  Object is list
            if not isinstance(FaceObject, list): 
                others = "FaceObject is not list"
                self.response_200([''], others, "8")
                return 
            ### 5, 解析Object，获得 jpg 和 Faceid列表, 保存图片
            ret = self.process_xxxObject(pictype, picpath, FaceObject)
            if ret == -1:
                return
            # 7, 200 OK
            ret = self.response_Create(self.FaceIDs) 
            # 8, save all json
            if save_json == 1:   
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, self.SourceID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)        
                if loglevel > 0:
                    jsonlogmsg = '\n命名：SourceID = %s'%self.SourceID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_face(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True
                
    def process_persons_request(self):    
        # 处理 persons 请求 , call process_xxxObject
        pictype = 'PersonObject'
        picpath = 'GAHttps/person_jpg'    
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:    
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return  
            self.savegadb(json_dict)  
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return 
            # 3，检查参数, PersonListObject PersonObject
            PersonListObject = json_dict.get("PersonListObject")
            if PersonListObject == None:
                others = "not found PersonListObject"                
                self.response_200([''], others, "8")
                return  
            # 2, Object
            PersonObject = json_dict["PersonListObject"].get("PersonObject")
            if PersonObject == None:  
                others = "not found PersonObject in PersonListObject"
                self.response_200([''], others, "8")
                return
            # 3, Object is list
            if not isinstance(PersonObject, list): 
                others = "PersonObject is not list"
                self.response_200([''], others, "8")
                return            
            ### 5, 解析Object，获得 jpg 和 Personid列表, 保存图片
            ret = self.process_xxxObject(pictype, picpath, PersonObject)
            if ret == -1:
                return
            # 7, 200 OK
            ret = self.response_Create(self.PersonIDs) 
            # 8, save all json
            if save_json == 1:   
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, self.SourceID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)
                if loglevel > 0:
                    jsonlogmsg = '\n命名：SourceID = %s'%self.SourceID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_person(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True
            
    def process_motors_request(self):    
        # 处理 MotorVehicles 请求 , call process_xxxObject        
        pictype = 'MotorVehicleObject'
        picpath = 'GAHttps/motorvehicle_jpg'    
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:    
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return 
            self.savegadb(json_dict)   
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return 
            # 3，检查参数, MotorVehicleListObject MotorVehicleObject
            MotorVehicleListObject = json_dict.get("MotorVehicleListObject")
            if MotorVehicleListObject == None:
                others = "not found MotorVehicleListObject"
                self.response_200([''], others, "8")
                return  
            # 2, Object
            MotorVehicleObject = json_dict["MotorVehicleListObject"].get("MotorVehicleObject")
            if MotorVehicleObject == None:  
                others = "not found MotorVehicleObject in MotorVehicleListObject"
                self.response_200([''], others, "8")
                return
            # 3, Object is list
            if not isinstance(MotorVehicleObject, list): 
                others = "MotorVehicleObject is not list"                
                self.response_200([''], others, "8")
                return 
            ### 5, 解析Object，获得 jpg 和 MotorVehicleid列表, 保存图片
            ret = self.process_xxxObject(pictype, picpath, MotorVehicleObject)
            if ret == -1:
                return
            # 7, 200 OK
            ret = self.response_Create(self.MotorVehicleIDs) 
            # 8, save all json
            if save_json == 1: 
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, self.SourceID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)
                if loglevel > 0:
                    jsonlogmsg = '\n命名：SourceID = %s'%self.SourceID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_MotorVehicle(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True            
            
    def process_nonmotors_request(self):    
        # 处理 NonMotorVehicles 请求 , call process_xxxObject        
        pictype = 'NonMotorVehicleObject'
        picpath = 'GAHttps/nonmotorvehicle_jpg'    
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:    
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return  
            self.savegadb(json_dict)  
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return
            # 3，检查参数, NonMotorVehicleListObject NonMotorVehicleObject
            NonMotorVehicleListObject = json_dict.get("NonMotorVehicleListObject")
            if NonMotorVehicleListObject == None:
                others = "not found NonMotorVehicleListObject"
                self.response_200([''], others, "8")
                return  
            # 2, Object
            NonMotorVehicleObject = json_dict["NonMotorVehicleListObject"].get("NonMotorVehicleObject")
            if NonMotorVehicleObject == None:  
                others = "not found NonMotorVehicleObject in NonMotorVehicleListObject"
                self.response_200([''], others, "8")
                return
            # 3, Object is list
            if not isinstance(NonMotorVehicleObject, list): 
                others = "NonMotorVehicleObject is not list"
                self.response_200([''], others, "8")
                return 
            ### 5, 解析Object，获得 jpg 和 NonMotorVehicleid列表, 保存图片
            ret = self.process_xxxObject(pictype, picpath, NonMotorVehicleObject)
            if ret == -1:
                return
            # 7, 200 OK
            ret = self.response_Create(self.NonMotorVehicleIDs) 
            # 8, save all json
            if save_json == 1:   
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, self.SourceID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)
                if loglevel > 0:
                    jsonlogmsg = '\n命名：SourceID = %s'%self.SourceID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_NonMotorVehicle(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True   
         
    def process_images_request(self):  
        picpath = 'GAHttps/image_jpg'    
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:  
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return  
            self.savegadb(json_dict)  
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return
            # 3，检查参数, ImageListObject Image
            ImageListObject = json_dict.get("ImageListObject")
            if ImageListObject == None:
                others = "not found ImageListObject"
                self.response_200([''], others, "8")
                return
            # 2, Image
            Image = json_dict["ImageListObject"].get("Image")
            if Image == None:  
                others = "not found Image in ImageListObject"
                self.response_200([''], others, "8")
                return
            # 3, Object is list
            if not isinstance(Image, list):  
                others = "Image is not list"
                self.response_200([''], others, "8")
                return
            for Image_dict in Image:
                # 6, 解析Info 获取ImageID shottime Data
                ImageInfo = Image_dict.get("ImageInfo")
                if ImageInfo == None:
                    others = "not found ImageInfo in Image"
                    self.response_200([''], others, "8")
                    return  
                ImageID = ImageInfo.get("ImageID")
                if ImageID == None:
                    others = "not found ImageID in ImageInfo"
                    self.response_200([''], others, "8")
                    return
                self.ImageIDs.append(ImageID)
                ShotTime = ImageInfo.get("ShotTime")  
                if ShotTime == None:
                    others = "not found ShotTime in ImageInfo"
                    self.response_200([''], others, "8")
                    return    
                Data_str = Image_dict.get("Data")
                if Data_str == None:
                    others = "not found Data in ImageInfo"
                    self.response_200([''], others, "8")
                    return  
                try:
                    jpg = base64.b64decode(Data_str.encode("utf-8"))
                except Exception as e:
                    GAlogging.error(self.ip_port + "Exception is：" + str(e))                    
                    others = "base64 decode error"
                    self.response_200([''], others, "1")
                    return   
                # 7 图片名称
                image_bigfile = '{}_{}_{}_Image.jpg'.format(ip, ImageID, ShotTime)   
                image_file = os.path.join(picpath, image_bigfile)
                jsonlogmsg = ''
                # 8， 保存json
                if save_json == 1:                                     
                    with open(image_file[:-4]+'.json', 'w', encoding='utf8') as f:
                        json.dump(Image_dict, f, ensure_ascii=False,indent=2)
                    jsonlogmsg += "\njson：{}".format(image_file[:-4]+'.json')
                if loglevel > 0:
                    msg = "Image picture:{}".format(image_file) + jsonlogmsg
                    msg += '\n命名: ImageID = %s'%ImageID + ', ShotTime = %s'%ShotTime
                    for k, v in ImageInfo.items():
                        if k == 'Data':
                            pass
                        else:
                            msg += '\n {}: {}'.format(k, v)
                    GAlogging.info(self.ip_port + msg)
                if os.path.isfile(image_file):
                    others = "有重名图片:{}".format(image_file)
                    GAlogging.warning(self.ip_port + others)
                    self.repeatpicsum += 1
                # 9 图片数量统计
                self.imgbigPicNums += 1
                if not jpg:
                    self.zeropicsum += 1
                    self.savedata(image_file, jpg)
                else:
                    if save_jpg == 1:  # 保存
                        self.savedata(image_file, jpg)  
                    if self.check_jpgformat(image_file, jpg) == False:
                        others = "jpg format error"
                        self.response_200([''], others, "6")
                        return                              
                ### 10, 解析ImageList 。。。
                ret = self.process_xxxListObject(picpath, Image_dict)
                if ret == False:
                    return  
            # 11, 200 OK
            ret = self.response_Create(self.ImageIDs) 
            # 12, save all json
            if save_json == 1: 
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, ImageID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)
                if loglevel > 0:
                    jsonlogmsg = '\n命名：ImageID = %s'%ImageID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_image(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True         
         
    def process_videoslices_request(self):  
        picpath = 'GAHttps/video_ps'    
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:  
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return   
            self.savegadb(json_dict) 
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return
            # 3，检查参数, VideoSliceListObject VideoSlice
            VideoSliceListObject = json_dict.get("VideoSliceListObject")
            if VideoSliceListObject == None:
                others = "not found VideoSliceListObject"
                self.response_200([''], others, "8")
                return
            # 2, VideoSlice
            VideoSlice = json_dict["VideoSliceListObject"].get("VideoSlice")
            if VideoSlice == None:  
                others = "not found VideoSlice in VideoSliceListObject"
                self.response_200([''], others, "8")
                return
            # 3, Object is list
            if not isinstance(VideoSlice, list):  
                others = "VideoSlice is not list"
                self.response_200([''], others, "8")
                return
            for VideoSlice_dict in VideoSlice:
                # 6, 解析Info 获取VideoID BeginTime Data
                VideoSliceInfo = VideoSlice_dict.get("VideoSliceInfo")
                if VideoSliceInfo == None:
                    others = "not found VideoSliceInfo in VideoSlice"
                    self.response_200([''], others, "8")
                    return  
                VideoID = VideoSliceInfo.get("VideoID")
                if VideoID == None:
                    others = "not found VideoID in VideoSliceInfo"
                    self.response_200([''], others, "8")
                    return
                self.VideoIDs.append(VideoID)
                BeginTime = VideoSliceInfo.get("BeginTime")  
                if BeginTime == None:
                    others = "not found BeginTime in VideoSliceInfo"
                    self.response_200([''], others, "8")
                    return   
                EndTime = VideoSliceInfo.get("EndTime")  
                if EndTime == None:
                    others = "not found EndTime in VideoSliceInfo"
                    self.response_200([''], others, "8")
                    return    
                Data_str = VideoSlice_dict.get("Data")
                if Data_str == None:
                    others = "not found Data in VideoSliceInfo"
                    self.response_200([''], others, "8")
                    return  
                try:
                    psdata = base64.b64decode(Data_str.encode("utf-8"))
                except Exception as e:
                    GAlogging.error(self.ip_port + "Exception is：" + str(e))
                    others = "base64 decode error"
                    self.response_200([''], others, "1")
                    return   
                # 7 图片名称
                VideoSlice_bigfile = '{}_{}_{}_{}_VideoSlice.ps'.format(ip, VideoID, BeginTime, EndTime)   
                VideoSlice_file = os.path.join(picpath, VideoSlice_bigfile)                             
                # 8， 保存json
                jsonlogmsg = ''
                if save_json == 1:                                     
                    with open(VideoSlice_file[:-3]+'.json', 'w', encoding='utf8') as f:
                        json.dump(VideoSlice_dict, f, ensure_ascii=False,indent=2)
                    jsonlogmsg += "\njson：{}".format(VideoSlice_file[:-3]+'.json')
                if loglevel > 0:
                    msg = "VideoSlice:{}".format(VideoSlice_file) + jsonlogmsg
                    msg += '\n命名: VideoID = %s'%VideoID + ', BeginTime = %s'%BeginTime + ', EndTime = %s'%EndTime
                    for k, v in VideoSliceInfo.items():
                        if k == 'Data':
                            pass
                        else:
                            msg += '\n {}: {}'.format(k, v)
                    GAlogging.info(self.ip_port + msg)
                if os.path.isfile(VideoSlice_file):
                    others = "有重名ps:{}".format(VideoSlice_file)
                    GAlogging.warning(self.ip_port + others)                
                # 9 数量统计
                self.VideoNums += 1
                if save_jpg == 1:  # 保存
                    self.savedata(VideoSlice_file, psdata)   
                ### 10, 解析VideoSliceList 。。。
                ret = self.process_xxxListObject(picpath, VideoSlice_dict)
                if ret == False:
                    return  
            # 11, 200 OK
            ret = self.response_Create(self.VideoIDs) 
            # 12, save all json
            if save_json == 1: 
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, VideoID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)
                if loglevel > 0:
                    jsonlogmsg = '\n命名：VideoID = %s'%VideoID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_video(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True   
            
    def process_files_request(self):  
        picpath = 'GAHttps/file'    
        ip = self.client_address[0]  
        # 1, 读body数据， 没有读到 内部已经返回200 错误
        json_dict = self.read_httpContent()
        if json_dict:  
            # 2, 检查注册时间 和 认证
            if self.check_regtime_auth() == False:
                return  
            self.savegadb(json_dict)                 
            if noparseID == 1: # 不解析Object，直接返回200 OK
                self.response_Create(['0'])
                return
            # 3，检查参数, FileListObject File
            FileListObject = json_dict.get("FileListObject")
            if FileListObject == None:
                others = "not found FileListObject"
                self.response_200([''], others, "8")
                return
            # 2, File
            File = json_dict["FileListObject"].get("File")
            if File == None:  
                others = "not found File in FileListObject"
                self.response_200([''], others, "8")
                return
            # 3, Object is list
            if not isinstance(File, list):  
                others = "File is not list"
                self.response_200([''], others, "8")
                return
            for File_dict in File:
                # 6, 解析Info 获取FileID  Data
                FileInfo = File_dict.get("FileInfo")
                if FileInfo == None:
                    others = "not found FileInfo in File"
                    self.response_200([''], others, "8")
                    return  
                FileID = FileInfo.get("FileID")
                if FileID == None:
                    others = "not found FileID in FileInfo"
                    self.response_200([''], others, "8")
                    return
                self.FileIDs.append(FileID)
                FileName = FileInfo.get("FileName")  
                if FileName == None:
                    others = "not found FileName in FileInfo"
                    self.response_200([''], others, "8")
                    return   
                Data_str = File_dict.get("Data")
                if Data_str == None:
                    others = "not found Data in FileInfo"
                    self.response_200([''], others, "8")
                    return  
                try:
                    filedata = base64.b64decode(Data_str.encode("utf-8"))
                except Exception as e:
                    GAlogging.error(self.ip_port + "Exception is：" + str(e))
                    others = "base64 decode error"
                    self.response_200([''], others, "1")
                    return   
                # 7 文件名称
                File_bigfile = '{}_{}_{}'.format(ip, FileID, FileName)   
                File_file = os.path.join(picpath, File_bigfile)                              
                # 8， 保存json
                jsonlogmsg = ''
                if save_json == 1:                                     
                    with open(File_file[:-4]+'.json', 'w', encoding='utf8') as f:
                        json.dump(File_dict, f, ensure_ascii=False,indent=2)
                    jsonlogmsg += "\njson：{}".format(File_file[:-4]+'.json')
                if loglevel > 0:
                    msg = "File:{}".format(File_file) + jsonlogmsg
                    msg += '\n 命名: FileID = %s'%FileID + ', FileName = %s'%FileName
                    for k, v in FileInfo.items():
                        if k == 'Data':
                            pass
                        else:
                            msg += '\n {}: {}'.format(k, v)
                    GAlogging.info(self.ip_port + msg)
                if os.path.isfile(File_file):
                    others = "有重名txt:{}".format(File_file)
                    GAlogging.warning(self.ip_port + others)    
                # 9 数量统计
                self.FileNums += 1
                if save_jpg == 1:  # 保存
                    self.savedata(File_file, filedata)  
                ### 10, 解析FileList 。。。
                ret = self.process_xxxListObject(picpath, File_dict)
                if ret == False:
                    return  
            # 11, 200 OK
            ret = self.response_Create(self.FileIDs) 
            # 12, save all json
            if save_json == 1: 
                curtime = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
                jfile = '{}_{}__PC{}_All.json'.format(ip, FileID, curtime)
                jsonfile = os.path.join(picpath, jfile)
                with open(jsonfile, 'w', encoding='utf8') as f:
                    json.dump(json_dict, f, ensure_ascii=False,indent=2)
                if loglevel > 0:
                    jsonlogmsg = '\n命名：FileID = %s'%FileID + ', PC时间 = %s'%curtime
                    retmsg = get_jsonkeys.get_file(json_dict)
                    GAlogging.info(self.ip_port + " 保存所有json:{}".format(jsonfile) + jsonlogmsg + '\n'+ retmsg)
            if ret == True:
                return True 
        
    def close_connect(self):
        # return True 关闭连接
        if usegaini == 1:
            if os.path.isfile("ga.ini"):
                conf = configparser.ConfigParser()
                conf.read('ga.ini')
                try:
                    closeconn = conf.get("closeconn","close")
                    if closeconn == '1':
                        conn=self.request
                        GAlogging.info(self.ip_port + "关闭连接")
                        conn.close()  
                        return True   
                except Exception as e:
                    GAlogging.warning(self.ip_port + 'ga.ini 文件有错误, ' + '\n except:' + str(e)) 
                    return False
            else:
                GAlogging.warning(self.ip_port + '没有 ga.ini 文件')
        return False
        
    def do_POST(self):          
        self.init_param()   
        self.ip_port = "{} {} : ".format(self.client_address, self.requestline)
        ret = False
        #GAlogging.info(self.ip_port + "")
        #GAlogging.info(self.ip_port + "-----------Start-------------------")
        try:
            if loglevel > 0:
                self.getThreads()        
            if "POST /VIID/System/Register " in self.requestline:
                GAlogging.info(self.ip_port + "*** 注册 ***")
                self.RequestURL = "/VIID/System/Register"
                self.process_register_request()                        
            elif "POST /VIID/System/UnRegister " in self.requestline:
                GAlogging.info(self.ip_port + "*** 注销 ***")
                self.RequestURL = "/VIID/System/UnRegister"
                self.process_unregister_request()                        
            elif "POST /VIID/System/Keepalive " in self.requestline:
                GAlogging.info(self.ip_port + "*** 心跳 ***")
                self.RequestURL = "/VIID/System/Keepalive"
                self.process_keepalive_request()                        
            elif "POST /VIID/Faces " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传人脸图片 ***") 
                self.RequestURL = "/VIID/Faces"
                if self.close_connect():
                    return  
                ret = self.process_faces_request()
            elif "POST /VIID/Persons " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传人员资源 ***") 
                self.RequestURL = "/VIID/Persons"
                if self.close_connect():
                    return  
                ret = self.process_persons_request()
            elif "POST /VIID/MotorVehicles " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传机动车 ***") 
                self.RequestURL = "/VIID/MotorVehicles"
                if self.close_connect():
                    return  
                ret = self.process_motors_request()
            elif "POST /VIID/NonMotorVehicles " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传非机动车 ***")  
                self.RequestURL = "/VIID/NonMotorVehicles"
                if self.close_connect():
                    return  
                ret = self.process_nonmotors_request()
            elif "POST /VIID/Images " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传图像资源 ***")   
                self.RequestURL = "/VIID/Images"
                if self.close_connect():
                    return  
                ret = self.process_images_request()    
            elif "POST /VIID/Files " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传文件 ***")   
                self.RequestURL = "/VIID/Files"
                if self.close_connect():
                    return  
                ret = self.process_files_request()
            elif "POST /VIID/VideoSlices " in self.requestline:
                GAlogging.info(self.ip_port + "*** 上传视频片段 ***")  
                self.RequestURL = "/VIID/VideoSlices"
                if self.close_connect():
                    return  
                ret = self.process_videoslices_request()
            else:
                GAlogging.info(self.ip_port + "----------其他消息-------------")
                others = "not support " + self.requestline
                self.response_200([''], others, "6")            
            if ret:
                resultLock.acquire()
                self.set_device_result()
                if resultLock.locked():
                    resultLock.release()
                
            if show_registertime == 1:
                GAlogging.info(self.ip_port + '当前注册的所有设备信息')
                fetch_device("", "") 
                """
                for k, v in device_registerinfo.items():
                    result = v.get('result')
                    if result:
                        posttypes = ''
                        for _ in result.keys():
                            posttypes += _ + ';'
                        retmsg += fetch_device(k, posttypes)    
                if retmsg:
                    GAlogging.info(self.ip_port + '当前注册的所有设备信息\n' + retmsg)
                """
        except Exception as e:
            GAlogging.error(self.ip_port + ' 出现异常:' + str(e))
            
    def printids(self):
        # 打印ID和图片统计信息
        reusltmsg = '当前数据包的ID，图片数量统计信息\n'
        #reusltmsg += 'DeviceID:{}\n'.format(self.DeviceID)
        reusltmsg += 'DeviceIDs:{}\n'.format(self.DeviceIDs)
        #reusltmsg += 'SourceID:{}\n'.format(self.SourceID)
        reusltmsg += 'SourceIDs:{}\n'.format(self.SourceIDs)
        #reusltmsg += 'FaceID:{}\n'.format(self.FaceID)
        reusltmsg += 'FaceIDs:{}\n'.format(self.FaceIDs)
        #reusltmsg += 'PersonID:{}\n'.format(self.PersonID)
        reusltmsg += 'PersonIDs:{}\n'.format(self.PersonIDs)
        #reusltmsg += 'MotorVehicleID:{}\n'.format(self.MotorVehicleID)
        reusltmsg += 'MotorVehicleIDs:{}\n'.format(self.MotorVehicleIDs)
        #reusltmsg += 'NonMotorVehicleID:{}\n'.format(self.NonMotorVehicleID)
        reusltmsg += 'NonMotorVehicleIDs:{}\n'.format(self.NonMotorVehicleIDs)
        #reusltmsg += 'FileID:{}\n'.format(self.FileID)
        reusltmsg += 'FileIDs:{}\n'.format(self.FileIDs)        
        #reusltmsg += 'VideoID:{}\n'.format(self.VideoID)
        reusltmsg += 'VideoIDs:{}\n'.format(self.VideoIDs)
        #reusltmsg += 'ImageID:{}\n'.format(self.ImageID)
        reusltmsg += 'ImageIDs:{}\n'.format(self.ImageIDs)
        reusltmsg += 'numSubImageInfoObject:{}\n'.format(self.numSubImageInfoObject)  # 图片总数量
        reusltmsg += 'facePicNums:{}\n'.format(self.facePicNums)    #face小图
        reusltmsg += 'personPicNums:{}\n'.format(self.personPicNums)  #person小图
        reusltmsg += 'motorPicNums:{}\n'.format(self.motorPicNums)  #机动车图
        reusltmsg += 'nonmotorPicNums:{}\n'.format(self.nonmotorPicNums)  #非机动车小图
        reusltmsg += 'imgbigPicNums:{}\n'.format(self.imgbigPicNums)  #image 大图
        reusltmsg += 'FileNums:{}\n'.format(self.FileNums)  # 文件数量        
        reusltmsg += 'VideoNums:{}\n'.format(self.VideoNums) # 录像数量
        reusltmsg += 'errpicsum:{}\n'.format(self.errpicsum) # 错误图片数量0
        reusltmsg += 'zeropicsum:{}\n'.format(self.zeropicsum) # 图片大小为0的数量0
        reusltmsg += 'repeatpicsum:{}\n'.format(self.repeatpicsum) # 
        GAlogging.info(self.ip_port + reusltmsg)

jpgfile_type = ["车辆大图", "车牌彩色小图", "车牌二值化图", "驾驶员面部特征图", \
                    "副驾驶面部特征图", "车标", "违章合成图", "过车合成图", \
                    "车辆特写图", "人员图", "人脸图", "非机动车图", \
                    "物品图", "场景图", "一般图片"] 
                    
def count_xxxObjectpics(xxxObject, count_jpgs):
    # 计算 FaceObject .. 不同type的图片数量
    reusltmsg = ''
    jpgnums = 0
    for x in range(15):
        jpgnums += count_jpgs[x]    
    if jpgnums > 0:
        reusltmsg += '\t    %s统计如下(%d):\n'%(xxxObject, jpgnums)
        reusltmsg += '\t    '
        for x in range(15):
            if count_jpgs[x] > 0:
                reusltmsg += '  {}:{}'.format(jpgfile_type[x], count_jpgs[x])
        reusltmsg += '\n'
    return reusltmsg
    
def count_jpgnums(count_jpgs, RequestURL):
    # 计算 jpg 数量 
    # count_jpgs: RequestURL的结果列表， RequestURL：/VIID/Faces
    reusltmsg = ''
    if "/VIID/Faces" == RequestURL:
        reusltmsg += '\t人脸:  数据包总数:{} 图片总数:{}\n'.format(count_jpgs[0],count_jpgs[1])
        reusltmsg += count_xxxObjectpics('FaceObject', count_jpgs[2])
    elif "/VIID/Persons" == RequestURL:
        reusltmsg += '\t人员:  数据包总数:{} 图片总数:{}\n'.format(count_jpgs[0],count_jpgs[1])
        reusltmsg += count_xxxObjectpics('PersonObject', count_jpgs[3])
    elif "/VIID/MotorVehicles" == RequestURL:
        reusltmsg += '\t机动车:  数据包总数:{} 图片总数:{}\n'.format(count_jpgs[0],count_jpgs[1])
        reusltmsg += count_xxxObjectpics('MotorVehicleObject', count_jpgs[4])
    elif "/VIID/NonMotorVehicles" == RequestURL:
        reusltmsg += '\t非机动车:  数据包总数:{} 图片总数:{}\n'.format(count_jpgs[0],count_jpgs[1])
        reusltmsg += count_xxxObjectpics('NonMotorVehicleObject', count_jpgs[5])
    elif RequestURL in ["/VIID/Images", "/VIID/Files", "/VIID/VideoSlices"]:
        if "/VIID/Images" == RequestURL:
            reusltmsg += '\t图像集合:  数据包总数:{} 图片总数:{} image全景图:{}\n'.format(count_jpgs[0],count_jpgs[1]+count_jpgs[6],count_jpgs[6])
        elif "/VIID/Files" == RequestURL:
            reusltmsg += '\t文件:  数据包总数:{} 图片总数:{} file数量:{}\n'.format(count_jpgs[0],count_jpgs[1],count_jpgs[6])
        elif "/VIID/VideoSlices" == RequestURL:
            reusltmsg += '\t视频片段:  数据包总数:{} 图片总数:{} video数量:{}\n'.format(count_jpgs[0],count_jpgs[1],count_jpgs[6])
        reusltmsg += count_xxxObjectpics('FaceObject', count_jpgs[2])
        reusltmsg += count_xxxObjectpics('PersonObject', count_jpgs[3])
        reusltmsg += count_xxxObjectpics('MotorVehicleObject', count_jpgs[4])
        reusltmsg += count_xxxObjectpics('NonMotorVehicleObject', count_jpgs[5])
    reusltmsg += '\t    [其中错误图片:{},大小为0的图片:{},重名图片:{}]\n'.format(count_jpgs[7],count_jpgs[8],count_jpgs[9])   
    return reusltmsg
    
def fetch_device(deviceips, posttypes):
    # 获取信息，提供给外部调用
    retmsg = ''
    if server_runtime[0] > 0:
        #retmsg += '服务器启动时间：%s\n'%time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(server_runtime[0]))
        retmsg += 'GA1400服务器(https)启动时间：%s\n'%str(datetime.datetime.fromtimestamp(server_runtime[0]))
    else:
        retmsg += 'GA1400服务器(https)未启动\n'
        return retmsg
    #retmsg += '当前时间: %s\n'%time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
    retmsg += '当前时间: %s\n'%str(datetime.datetime.now())
    # 1, 获得ip
    if len(deviceips.strip()) == 0:
        iplist = device_registerinfo.keys()
    else:
        iplist = deviceips.split(';')        
    for ip in iplist:
        ip = ip.strip()
        if ip:
            device = device_registerinfo.get(ip)
            if device == None:  # 没有注册
                retmsg += "  设备IP: %s not register\n"%ip
            else:
                if device.get('registertime') == None:
                    retmsg += "  设备IP: %s not register success!\n"%ip
                else:
                    # 打印 注册时间， 注册时间列表， 刷新注册时间列表， 注销时间列表
                    #retmsg += '##'*30 + '\n' 
                    retmsg += '  设备IP: {}\n'.format(ip)
                    #regtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(device.get('registertime')))
                    regtime = str(datetime.datetime.fromtimestamp(device.get('registertime')))
                    retmsg += '    注册时间: {}\n'.format(regtime)
                    #retmsg += 'nonce: {}\n'.format(device.get('nonce'))
                    if device.get('record_registertime'):
                        retmsg += '    注册时间列表: [ '
                        nums = 0
                        timelist = device.get('record_registertime')
                        lasttag = len(timelist)
                        for thistime in timelist:
                            if nums%6 == 5:
                                retmsg += '\n      '
                            nums += 1
                            if nums == lasttag:
                                #retmsg += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(thistime))
                                retmsg += str(datetime.datetime.fromtimestamp(thistime))
                            else:
                                #retmsg += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(thistime)) + ' , '
                                retmsg += str(datetime.datetime.fromtimestamp(thistime)) + ' , '
                        retmsg += ' ] \n'
                    if device.get('refresh_registertime'):
                        retmsg += '    刷新注册时间列表: [ '
                        nums = 0
                        timelist = device.get('refresh_registertime')
                        lasttag = len(timelist)
                        for thistime in timelist:
                            if nums%6 == 5:
                                retmsg += '\n      '
                            nums += 1
                            if nums == lasttag:
                                #retmsg += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(thistime))
                                retmsg += str(datetime.datetime.fromtimestamp(thistime))
                            else:
                                #retmsg += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(thistime)) + ' , '
                                retmsg += str(datetime.datetime.fromtimestamp(thistime)) + ' , '
                        retmsg += ' ] \n'
                    if device.get('unregistertime'):
                        retmsg += '    注销时间列表: [ '
                        nums = 0
                        timelist = device.get('unregistertime')
                        lasttag = len(timelist)
                        for thistime in timelist:
                            if nums%6 == 5:
                                retmsg += '\n      '
                            nums += 1
                            if nums == lasttag:
                                #retmsg += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(thistime))
                                retmsg += str(datetime.datetime.fromtimestamp(thistime))
                            else:
                                #retmsg += time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(thistime)) + ' , '
                                retmsg += str(datetime.datetime.fromtimestamp(thistime)) + ' , '
                        retmsg += ' ] \n'
                    #retmsg += '--'*30 + '\n'
                    result = device.get('result')
                    if not result:
                        retmsg += '\t  not pics\n'                        
                    else:
                        # 打印结果
                        if len(posttypes.strip()) == 0:
                            posttypelist = result.keys()
                        else:
                            posttypelist = posttypes.split(';')
                        # 根据 POST 类型 获取# Faces, Persons, ...
                        for posttype in posttypelist:  
                            posttype = posttype.strip()
                            if posttype:
                                if posttype.startswith('/VIID/'):
                                    RequestURL = posttype
                                else:
                                    RequestURL = '/VIID/' + posttype
                                if result.get(RequestURL) == None:  
                                    retmsg += "\t  not found %s\n"%(RequestURL)
                                else:
                                    retmsg += count_jpgnums(result.get(RequestURL), RequestURL)  
    #GAlogging.info('{}'.format(device_registerinfo))
    GAlogging.info('{}'.format(retmsg))
    return retmsg

if __name__ == "__main__":
    ga = GAHttps()
    ga.run(IP,PORT)

